package cn.ycc1.boot3thread.controller;

import cn.ycc1.boot3thread.common.MyRunnable;
import cn.ycc1.boot3thread.config.CompletableTask;
import cn.ycc1.boot3thread.user.domain.User;
import cn.ycc1.boot3thread.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 多线程测试
 * @author ycc
 * @date 2024/3/15
 */
@Slf4j
@RestController
@RequestMapping("/thread")
@RequiredArgsConstructor
public class ThreadController {

    private final Executor myCompletableTaskExecutor;
    private final UserService userService;

    private final ReentrantLock lock = new ReentrantLock();

    private static final Logger logger= LoggerFactory.getLogger(ThreadController.class);

    /**
     * 测试1
     * @return
     */
    @GetMapping("/test")
    public String test() {

        CompletableTask.allOf(
                myCompletableTaskExecutor,
                () -> {
                    thread1();
                },
                () -> {
                    thread2();
                }
        );
        return "test thread";
    }

    private void thread2() {
        CompletableTask.allOf(
                myCompletableTaskExecutor,
                () -> {
                    lock.lock();
                    try {
                        this.updateUser(2L, 1L);
                    } finally {
                        lock.unlock();
                    }
                },
                () -> {
                    lock.lock();
                    try {
                        this.updateUser(2L, 2L);
                    } finally {
                        lock.unlock();
                    }
                }
        );
        System.out.println("------------thread2");
    }

    private void thread1() {
        CompletableTask.allOf(
                myCompletableTaskExecutor,
                () -> {
                    lock.lock();
                    try {
                        this.updateUser(2L, 3L);
                    } finally {
                        lock.unlock();
                    }
                },
                () -> {
                    lock.lock();
                    try {
                        this.updateUser(2L, 4L);
                    } finally {
                        lock.unlock();
                    }
                }
        );
        System.out.println("------------thread1");
    }

    /**
     * 更新用户的字段值
     *
     * @param uid
     * @param amount
     * @return
     */
    @Transactional
    protected Boolean updateUser(Long uid, Long amount) {
        User user = userService.getById(uid);
        user.setDeptId(user.getDeptId() + amount);
        return userService.updateById(user);
    }

    /**
     * 测试2
     * @return
     */
    @GetMapping("/test2")
    public String test2() {

        System.out.println("--------------线程接口测试---------------------");
        CompletableTask.allOf(
                myCompletableTaskExecutor,
                () -> {
                    System.out.println("-----------线程接口测试-测试多线程执行1--------------");
                },
                () -> {
                    System.out.println("-----------线程接口测试-测试多线程执行2--------------");
                }
        );
        return "test2 thread";
    }

    /**
     * 测试3-匿名类实现自定义接口
     * @return
     */
    @GetMapping("/test3")
    public String test3() {
        log.info("测试日志写入");
        logger.info("测试日志写入-logger");

        // 测试匿名类实现自定义接口
        MyRunnable myobj = new MyRunnable() {
            private final String name = "test MyRunnable";

            @Override
            public String test() {
                System.out.println(name);
                return name;
            }
        };
        return myobj.test();
    }

    public String testBak() {

        CompletableTask.allOf(
                myCompletableTaskExecutor,
                () -> {
                    thread1();
                },
                () -> {
                    thread2();
                },
//                new Task(),
                new Runnable() {
                    private final AtomicLong count1 = new AtomicLong(0L);
                    @Override
                    public void run() {
                        System.out.println("test_" + count1.getAndIncrement());
                    }
                },
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("test new Runnable() no lambda running");
                    }
                }
        );
        return "test thread";
    }

}
